package org.water.sys.web;

import java.util.Collection;

import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.SavedRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.water.base.entity.R;
import org.water.base.web.BaseController;
import org.water.common.bind.annotation.CurrentUser;
import org.water.common.bind.annotation.MethodDesc;
import org.water.common.param.AppSysParam;
import org.water.common.param.ConstParams;
import org.water.common.shiro.UserCookie;
import org.water.common.util.StringUtil;
import org.water.sys.entity.SysUser;
import org.water.sys.service.UserService;

/**
 * 登陆
 * @author qzy
 *
 */
@Controller
@RequestMapping("/login")
public class LoginController extends BaseController {

	@Autowired
	private UserService userService;
	@Autowired
	private CacheManager cacheManager;
	@Autowired
	private SessionDAO sessionDAO;
	
	private static Logger logger=LogManager.getLogger(LoginController.class);
	/**
	 * 登录密码重试缓存
	 */
	private Cache<String, Integer> passwordRetryCache=null;
	
	public LoginController() {
		// TODO Auto-generated constructor stub
	}
	/**
	 * 登陆界面
	 * @param model
	 * @return
	 */
	//@RequestMapping("/index")
	public String index(Model model,HttpServletRequest request,HttpServletResponse response)
	{
//		FormAuthenticationFilter s;
		response.setHeader("Content-Type", "text/html;charset=UTF-8");
		model.addAttribute("rememberMe", SecurityUtils.getSubject().isRemembered());
		String userName=request.getParameter("userName");
		if(passwordRetryCache==null) passwordRetryCache=cacheManager.getCache("passwordRetryCache");
		if(!StringUtil.isEmpty(userName))
		{
			Integer pwdRestryCount=passwordRetryCache.get(userName);
			pwdRestryCount=(pwdRestryCount!=null?pwdRestryCount:0);
			if(pwdRestryCount>=1) model.addAttribute("showCaptch",true);
		}
		return "welcome/login/login";
	}
	/**
	 * 登录 
	 * @param model
	 * @param user
	 * @return
	 */
	@MethodDesc(name="用户登录",value="开始登录")
	@RequestMapping("/in")
	public R login(Model model,SysUser user,HttpServletRequest request,HttpServletResponse response)
	{
		//shiro登陆
		Subject subject=SecurityUtils.getSubject();
		//String pwd=new String(Base64.getDecoder().decode(user.getPassword()));
		//user.setPassword(pwd);
//		Object r=subject.isRemembered();
//		Object t=subject.isAuthenticated();
		String rememberMeStr=request.getParameter("rememberMe");
		Boolean rememberMe=StringUtil.toBoolean(rememberMeStr);
		UsernamePasswordToken token=new UsernamePasswordToken(user.getUserName(), user.getPassword());
		token.setRememberMe(rememberMe);
		String url="welcome/login/login";
		String failMsg="";
		boolean auth=true;
		String code=request.getParameter("authCode");
		if(passwordRetryCache==null) passwordRetryCache=cacheManager.getCache("passwordRetryCache");
		Integer pwdRestryCount=passwordRetryCache.get(user.getUserName());
		pwdRestryCount=(pwdRestryCount!=null?pwdRestryCount:0);
		Object authCode=request.getSession().getAttribute(ConstParams.KEY_CAPTCHA);
		if(StringUtil.isEmptyObj(user.getUserName()))
		{
			failMsg="用户名不能为空！";
			auth=false;
		}
		else if(StringUtil.isEmptyObj(user.getPassword()))
		{
			failMsg="登录密码不能为空！";
			auth=false;
		}
		else if(StringUtil.isEmptyObj(code))
		{
			failMsg="验证码不能为空！";
			auth=false;
		}
		else if(code==null || authCode==null || !authCode.equals(code.toLowerCase()))
		{
			failMsg="验证码错误！";
			auth=false;
		}
		else if(pwdRestryCount>=AppSysParam.USER_RETRY_PWD)
		{
			failMsg="您已登录错误"+AppSysParam.USER_RETRY_PWD+"次，请10分钟后再次登录！";
			auth=false;
		}
		SysUser sysUser=userService.findUserByUserName(user.getUserName());
		if(sysUser==null)
		{
			failMsg="用户名不存在！";
			auth=false;
		}
		else if(1!=sysUser.getUsable())
		{
			failMsg="该用户已被禁用，请联系管理员！";
			auth=false;
		}
		else{
			
			try
			{
				if(auth==true)
				{
					checkSession(user.getUserName());
					subject.login(token);
					//登录成功，去掉错误次数
					passwordRetryCache.remove(user.getUserName());
					String refrerer=request.getHeader("referer"); 
					SavedRequest savedRequest=getSavedRequest(request);
					if(savedRequest!=null && !savedRequest.getMethod().toLowerCase().equals("post")) 
					{
					   url="redirect:"+savedRequest.getRequestUrl();
					   String ctx=request.getContextPath();
					   url=url.replace(ctx, "");
					}
					else if(refrerer!=null && !refrerer.contains("/login"))
					{
						url="redirect:"+refrerer;
					}
					else
					{
						url="redirect:/admin/index";
					}
					SysUser result=(SysUser) subject.getPrincipal();
					request.getSession().setAttribute(ConstParams.CURRENT_USER, result);
					String userName=!StringUtil.isEmpty(result.getAliasName()) ?result.getAliasName() : result.getUserName();
					request.getSession().setAttribute(ConstParams.CURRENT_USERNAME, userName);
					request.getSession().setAttribute(ConstParams.CURRENT_USER_ID, result.getId());
				}
			}
			catch(Exception e)
			{
				failMsg="用户名或密码错误！";
				pwdRestryCount=pwdRestryCount+1;
				passwordRetryCache.put(user.getUserName(),pwdRestryCount) ;
				//e.printStackTrace(); IncorrectCredentialsException
			}
			
			//移出用户菜单缓存
			/**Cache<Object, Object> userOwnResoucrce=cacheManager.getCache("userOwnResoucrce");
			if(userOwnResoucrce!=null)
			{
				//Object keys=userOwnResoucrce.keys();
				userOwnResoucrce.remove(user.getId());
				logger.info("清除用户的菜单缓存  "+user.getId());
			}**/
		}
		if(!StringUtil.isEmpty(failMsg)) model.addAttribute("failMsg",failMsg);
		if(pwdRestryCount>=1) model.addAttribute("showCaptch",true);
		request.setAttribute("rememberMe", SecurityUtils.getSubject().isRemembered());
		//ApplicationContext app = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
		//登录成功 设置用户cookie
		UserCookie.setUserCookie(user, request, response);
		
		logger.info("session:"+request.getSession().getId()+" 开始登录"+":"+("".equals(failMsg)?"登录成功":failMsg));
		
		return R.instance().setMsg(failMsg).setData(StringUtils.isEmpty(failMsg)?request.getSession().getId():"").setSuccess(StringUtils.isEmpty(failMsg)?true:false);
	}
	
	/**
	 * 退出
	 * @param model
	 * @param user
	 * @param request
	 * @return
	 */
//	@CacheEvict(value="userOwnResoucrce",key="#user.id")
	@MethodDesc(name="用户登录",value="退出登录")
	@RequestMapping("/out")
	public R loginOut(Model model,@CurrentUser SysUser user,HttpServletRequest request,HttpServletResponse response)
	{
		
		HttpSession session=request.getSession();
		session.removeAttribute(ConstParams.CURRENT_USER);
		session.removeAttribute(ConstParams.CURRENT_USERNAME);
		SecurityUtils.getSubject().logout();
		logger.info("退出登录");
		
		return R.instance().setSuccess(true);
	}
	/**
	 * 获取shiro验证前地址
	 * @param request
	 * @return
	 */
	private SavedRequest getSavedRequest(ServletRequest request) {  
	    SavedRequest savedRequest = null;  
	    Subject subject = SecurityUtils.getSubject();  
	    Session session = subject.getSession(false);  
	    if (session != null) {  
	        savedRequest = (SavedRequest) session.getAttribute("shiroSavedRequest");  
	    }  
	    return savedRequest;  
	}  
	/**
	 * 检查是否用户多登录
	 * @param userName
	 */
	private void checkSession(String userName)
	{
		if(AppSysParam.USER_MUTLI_LOGIN==false) //用户单登录 
		{
			Collection<Session> sessions= sessionDAO.getActiveSessions();
			for(Session session:sessions)
			{
				SysUser user=(SysUser)session.getAttribute(ConstParams.CURRENT_USER);
				if(user!=null && userName.equals(user.getUserName()))
				{
					session.setTimeout(0);
					break;
				}
			}
		}
	}
}
